package com.hsgene.order.controller;

import com.hsgene.common.util.character.CharactersConstant;
import com.hsgene.common.util.excle.ExcelData;
import com.hsgene.common.util.excle.ExcelImportBean;
import com.hsgene.common.util.excle.ExportExcelUtils;
import com.hsgene.common.util.result.ApiResult;
import com.hsgene.order.condition.SettlementCondition;
import com.hsgene.order.condition.SettlementExportCondition;
import com.hsgene.order.config.YmlConfig;
import com.hsgene.order.constants.ExportType;
import com.hsgene.order.constants.SettlementErrorCode;
import com.hsgene.order.domain.reconciliation.ReconciliationConditionDto;
import com.hsgene.order.domain.reconciliation.ReconciliationListInfo;
import com.hsgene.order.dto.v1.OrderSettlementDto;
import com.hsgene.order.service.ConsoleOrderService;
import com.hsgene.order.service.ReconciliationService;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 导出
 *
 * @author wxf
 * @date 2018/12/21 16:47
 **/
@RestController
@RequestMapping("/v1.0/genetic/testing")
public class ExportController {

    /**
     * Log
     */
    private Logger LOGGER = LogManager.getLogger(ExportController.class);

    @Resource
    private ConsoleOrderService consoleOrderService;

    @Resource
    private ReconciliationService reconciliationService;

    /**
     * 结算
     */
    private Map<String, String> settlementColumMap;

    /**
     * 对账
     */
    private Map<String, String> reconciliationColumMap;

    @Resource
    private YmlConfig ymlConfig;

    /**
     * 结算必导出的列
     */
    @Value("${settlement.export.field.name}")
    private String seMustExportField;

    //初始化列和字段映射关系
    @PostConstruct
    private void init() {
        settlementColumMap = initMap(ymlConfig.getSettlementName());
        reconciliationColumMap = initMap(ymlConfig.getReconciliatioNname());
    }

    private Map<String, String> initMap(String[] arrays) {
        Map<String, String> map = new LinkedHashMap<>();
        for (String values : arrays) {
            String[] arrVal = values.split(CharactersConstant.COMMA_COLON);
            map.put(arrVal[1], arrVal[0]);
        }
        return map;
    }

    /**
     * 获取导出列信息
     *
     * @param exportType 导出类型(结算settlement、对账reconciliation)
     * @return
     */
    @GetMapping("export/field")
    public ApiResult<Map<String, String>> getExportColum(String exportType) {
        if (StringUtils.isEmpty(exportType)) {
            return ApiResult.fail(SettlementErrorCode.EXPORT_TYPE_IS_NOT_NULL);
        }
        if (ExportType.SETTLEMENT.getType().equals(exportType)) {
            return new ApiResult(200, "success", "获取导出列信息", settlementColumMap);
        } else if (ExportType.RECONCILIATION.getType().equals(exportType)) {
            return new ApiResult(200, "success", "获取导出列信息", reconciliationColumMap);
        }
        return new ApiResult(200, "success", "获取导出列信息", new HashMap<>());
    }

    /**
     * 获取导入模板
     *
     * @param response
     * @throws Exception
     */
    @GetMapping("settlement/import/template")
    public void getTemplate(String fileName, HttpServletResponse response) throws Exception {
        try {
            if (StringUtils.isEmpty(fileName)) {
                response.setCharacterEncoding("utf-8");
                response.sendError(80003, SettlementErrorCode.EXPORT_FILE_IS_NOT_NULL.getDescription());
                return;
            }
            Map<String, String> exportMap = getExportFieldToMap(Arrays.asList(seMustExportField.split
                    (CharactersConstant.COMMA_EN)), settlementColumMap);
            exportData(fileName, response, null, exportMap, "结算导出信息模板数据");
            LOGGER.info("download template is success...");
        } catch (Exception e) {
            LOGGER.error("download template is error...", e);
            response.sendError(80001, "下载模版失败");
        }
    }

    /**
     * 结算信息导出
     *
     * @param exportInfo ids
     * @param fileName   文件名
     * @param response   response
     */
    @GetMapping("settlement/export")
    public void export(SettlementCondition exportInfo, String fileName,
                       HttpServletResponse response) throws Exception {
        try {
            LOGGER.info("start export settlement...");
            int code = checkExportInfo(exportInfo, fileName, settlementColumMap);
            if (code != 0) {
                response.setCharacterEncoding("utf-8");
                response.sendError(code, SettlementErrorCode.getEnum(code).getDescription());
                return;
            }
            //判断列订单编号、实验室名称（机构名称）、实验项目（项目名称）、成本是否存在
            List<String> exportFields = exportInfo.getExportFields();
            for (String mustField : seMustExportField.split(CharactersConstant.COMMA_EN)) {
                if (!exportFields.contains(mustField)) {
                    response.sendError(80007, "必选列" + settlementColumMap.get(mustField) + "不在导出字段中");
                    return;
                }
            }
            List<OrderSettlementDto> exportInfos = consoleOrderService.getExportInfoByIds(exportInfo);
            //封装筛选的导出列
            Map<String, String> exportMap = getExportFieldToMap(exportFields, settlementColumMap);
            exportData(fileName, response, exportInfos, exportMap, "结算信息数据");
            LOGGER.info("export settlement is success...");
        } catch (Exception e) {
            LOGGER.error("export settlement is error...", e);
            response.sendError(80001, "导出结算信息数据失败");
        }
    }

    /**
     * 导出对账数据
     *
     * @param exportInfo 导出
     * @param response   response
     */
    @GetMapping("reconciliation/export")
    public void reconciliationExport(ReconciliationConditionDto exportInfo, String fileName,
                                     HttpServletResponse response) throws IOException {
        try {
            LOGGER.info("start reconciliation export...");
            int code = checkExportInfo(exportInfo, fileName, reconciliationColumMap);
            if (code != 0) {
                response.setCharacterEncoding("utf-8");
                response.sendError(code, SettlementErrorCode.getEnum(code).getDescription());
                return;
            }
            //查询数据导出
            List<ReconciliationListInfo> infos = reconciliationService.getExportInfo(exportInfo);
            Map<String, String> exportMap = getExportFieldToMap(exportInfo.getExportFields(), reconciliationColumMap);
            exportData(fileName, response, infos, exportMap, "对账信息数据");
            LOGGER.info("export reconciliation is success...");
        } catch (Exception e) {
            LOGGER.error("export reconciliation is error...", e);
            response.sendError(80004, "对账信息导出失败...");
        }
    }

    /**
     * 结算导入
     *
     * @param uploadFile
     * @return
     */
    @PostMapping("settlement/import")
    public ApiResult importSettlementFile(@RequestParam("file") MultipartFile uploadFile) {
        try {
            String fileName = uploadFile.getOriginalFilename();
            if (StringUtils.isEmpty(fileName)) {
                LOGGER.error("upload file is null");
                return ApiResult.fail(SettlementErrorCode.SETTLEMENT_IMPORT_FILE_IS_NOT_NULL);
            }
            //判断是否是xlsx文件
            if (!fileName.endsWith(".xlsx")) {
                LOGGER.error("only upload .xlsx file");
                return ApiResult.fail(SettlementErrorCode.SETTLEMENT_FILE_TYPE_ERROR);
            }
            LOGGER.info("upload file is :" + fileName);
            //导入数据解析
            ExcelImportBean data = ExportExcelUtils.importExcel(uploadFile, settlementColumMap, "costPrice");
            if (data.getData() instanceof String) {
                return ApiResult.fail(SettlementErrorCode.SETTLEMENT_IMPORT_IS_ERROR, data.getData());
            }
            if (data.getData() == null) {
                return ApiResult.fail(SettlementErrorCode.SETTLEMENT_IMPORT_IS_ERROR);
            }
            //校验成本更新
            List<Map<String, Object>> dataList = (List<Map<String, Object>>) data.getData();
            Boolean flag = consoleOrderService.updateSettlementInfo(dataList);
            if (flag == null) {
                LOGGER.warn("import settlement update is null");
                return new ApiResult(200, "success", "对账数据导入更新完成,但是无数据更新", flag);
            }
            if (flag) {
                LOGGER.info("import settlement update is success");
                return new ApiResult(200, "success", "对账数据导入更新成功", flag);
            }
            return ApiResult.fail(SettlementErrorCode.SETTLEMENT_IMPORT_IS_ERROR);
        } catch (Exception e) {
            LOGGER.error("import settlement file is error", e);
            return ApiResult.fail(SettlementErrorCode.SETTLEMENT_IMPORT_IS_ERROR);
        }
    }


    private Map<String, String> getExportFieldToMap(List<String> exportFields, Map<String, String> columMap) {
        Map<String, String> exportMap = new LinkedHashMap<>();
        for (String exportField : exportFields) {
            exportMap.put(exportField, columMap.get(exportField));
        }
        return exportMap;
    }

    private int checkExportInfo(SettlementExportCondition exportInfo, String fileName, Map<String, String> columMap) {
        if (exportInfo == null) {
            return 80004;
        }
        String exportType = exportInfo.getExportType();
        if (StringUtils.isEmpty(exportType)) {
            return 80002;
        }
        //导出选中
        List<String> rowIds = exportInfo.getExportRowIds();
        if (ExportType.SELECTED.getType().equals(exportType) && (rowIds == null || rowIds.isEmpty())) {
            return 80004;
        }
        //选择字段
        List<String> exportFields = exportInfo.getExportFields();
        if (exportFields == null || exportFields.isEmpty()) {
            return 80005;
        }
        //判断导出字段是否在列表字段中
        for (String field : exportFields) {
            if (!columMap.containsKey(field)) {
                return 80006;
            }
        }

        if (StringUtils.isEmpty(fileName)) {
            return 80003;
        }
        return 0;
    }

    private void exportData(String fileName, HttpServletResponse response, Object exportInfos,
                            Map<String, String> exportMap, String sheetName)
            throws IOException {
        response.setHeader("Content-Type", "application/vnd.ms-excel;charset=UTF-8");
        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()) + ".xlsx";
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8'zh_cn'" + fileName);
        ExcelData data = new ExcelData();
        data.setTitles(exportMap);
        data.setData(exportInfos);
        data.setSheetName(sheetName);
        ExportExcelUtils.exportExcel(data, response.getOutputStream());
    }
}